function DoubleLinkedListElement(data) {
	this.prevElement = null;
	this.nextElement = null;
	this.data = data;
}

DoubleLinkedListElement.prototype.cloneObj = function ()
{
    function F() {}
    F.prototype = this;
    return new F();
};

function DoubleLinkedList(opts) {
	this.length = 0;
	this.startElement;
	this.endElement;
	this.iterator = 0;
	
	/**
	 * add element to the end of queue
	 */	
	this.push = function(data) {
		var element = new DoubleLinkedListElement(data);
		element.id = this.iterator;
		this.iterator++;
		if (this.length == 0) {
			this.startElement = element;
			this.endElement = element;
		} else {
			element.prevElement = this.endElement;
			this.endElement.nextElement = element;
			this.endElement = element;
		}
		this.length++;
		return this.length;
	};
	
	this.toArray = function() {
		var array = new Array();
		var e = this.startElement.cloneObj();
		for(var j=0;j<i;j++) {
			e = e.cloneObj();
			array.push(e.data);
			e = e.nextElement;
		}
		return array;
	};
	
	/**
	 * pop last element - remove it and return its value
	 */
	
	this.pop = function(data) {
		var data = this.endElement.data;
		delete this.endElement;
		this.endElement = null;
		this.length --;
		return data;
	};
	
	/**
	 * insert element at i position
	 */
	
	this.insertAt = function(i, data) {
		if (this.length < i) { throw "Index too big - max number is "+this.length; }
		if (i<0) { throw "Index too small"; }
		
		if (this.length == i)
			return this.push(data);
		
		var prevElementElement = null;
		if (i != 0)
			var prevElementElement = this.getIteratorAt(i-1);
		
		var nextElementElement = this.getIteratorAt(i);
		
		var element = new DoubleLinkedListElement(data);
		element.id = this.iterator;
		this.iterator++;
		element.nextElement = nextElementElement;
		element.prevElement = prevElementElement;
		
		if (prevElementElement == null) {
			this.startElement = element;
			nextElementElement.prevElement = element;
		} else if (nextElementElement == null) {
			this.endElement = element;
			prevElementElement.nextElement = element;
		} else {
			prevElementElement.nextElement = element;
			nextElementElement.prevElement = element;
		}
		
		this.length ++;
		
	};
	
	/**
	 * overwrite value at i position
	 */
	
	this.setAt = function (i,data) {
		if (this.length < i) { throw "Index too big - max number is "+this.length; }
		if (i<0) { throw "Index too small"; }
		
		var e = this.getIteratorAt(i);
		e.data = data;
	}
	
	/**
	 * remove element at i position
	 */
	
	this.removeAt = function(i) {
		if (this.length < i) { throw "Index too big - max number is "+this.length; }
		
		var e = this.getIteratorAt(i);
		/*console.log(i, e);
		return;*/
		if (e.nextElement == null) {
			this.endElement = e.prevElement;
		} else {
			e.nextElement.prevElement = e.prevElement;
		}
		
		if (e.prevElement == null) {
			this.startElement = e.nextElement;
		} else {
			e.prevElement.nextElement = e.nextElement;
		}		
		
		e = null;
		this.length--;
		
	};
	
	/**
	 * getter
	 */
	
	this.getAt = function(i) {
		if (this.length < i) { throw "Index too big - max number is "+this.length; }
	
		var e = this.startElement.cloneObj(); 
		for(var j=0;j<i;j++) {
			e = e.cloneObj();
			e = e.nextElement;
		}
		
		return e.data;
	};
	
	/**
	 * getter
	 */
	
	this.getIteratorAt = function(i) {
		if (this.length < i) { throw "Index too big - max number is "+this.length; }
	
		var e = this.startElement.cloneObj(); 
		for(var j=0;j<i;j++) {
			if (j!=i-1) {
				e = e.cloneObj();
			}
			e = e.nextElement;
		}
		return e;
		
	};
}
